using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WozLib.Net;
using WozLib.UI.Ink.SketchCommands;
using System.Collections.Generic;
using System.Windows.Input;
using System.Collections.ObjectModel;
using System.Diagnostics;
using WozLib.UI.Containers;
using System.Windows.Ink;
using System.Threading;
using Microsoft.Win32;
using System.IO;
using System.Xml.Serialization;
using WozLib.UI.Ink;
using WozLib.WozCommands;
using WozLib.UI.Ink.SketchObjects;
using WozLib.UI.Ink.SketchProperties;
using WozLib.WozObjects;
using WOzTestUI.WozCommands;
using WOzTestUI.WozObjects;
using WozLib.UI.Ink.SketchElements;


namespace WOzTestUI
{
  /// <summary>
  /// Interaction logic for WizardWindow.xaml
  /// </summary>

  public partial class WizardWindow : Window, IServerObject, IListboxWindow
  {
    public Type[] _WizardWindowWozObjectTypes =
      new Type[] { 
        typeof(AudioPromptServerObject), 
        typeof(AudioToPlayServerObject),
        typeof(StringToSpeakServerObject),
        typeof(WizardWindowWozObject),
        typeof(ScratchWindowWozObject)
      };

    //these are now in the wozlib
    //typeof(ScreenServerObject)
    //typeof(ReplacementPadServerObject)

    public static RoutedCommand DiscardChangesCommand;

    public static RoutedCommand MaximizeRectGeometry;

    public static RoutedCommand MoveBackwardCommand;

    public static RoutedCommand MoveForwardCommand;

    public static RoutedCommand OpenFromImagesCommand;

    //ClientMirrorWindow _ClientMirrowWindow;

    WozServer _WozServer;

    SketchCommandReferences _ClientMirrorCommandReferences;

    //WozServerCommandReferences _GenericWozServerCommandReferences;

    // stack of server commands that represent the undo stack
    Stack<WozLib.WozCommands.WozCommand> _UndoStack = new Stack<WozLib.WozCommands.WozCommand>();

    // stack of server commands that represent the redo stack
    Stack<WozLib.WozCommands.WozCommand> _RedoStack = new Stack<WozLib.WozCommands.WozCommand>();

    // list of server commands that represent the entire history of the wizards actions
    List<WozLib.WozCommands.WozCommand> _WizardHistory = new List<WozLib.WozCommands.WozCommand>();
   
    // registry of all the WozObjects in the client mirror window
    SketchObjectRegistry _ClientMirrorWozObjectRegistry = new SketchObjectRegistry();

    HttpFileServer _HttpFileServer;
    Thread _FileServerThread;

    public ClientInkCanvas ClientRadarCanvas
    {
      get { return _ClientRadarCanvas; }
      set { _ClientRadarCanvas = value; }
    } private ClientInkCanvas _ClientRadarCanvas;
    private SketchCommandReferences _ClientRadarCommandReferences;
    private SketchObjectRegistry _ClientRadarSketchObjectRegistry;

    public WozScreenCollection WozScreens
    {
      get{return _WozScreens;}
      set{_WozScreens = value;}
    } WozScreenCollection _WozScreens;

    public ObjectDataProvider WozScreensProvider
    {
      get { return _WozScreensProvider; }
      set { _WozScreensProvider = value; }
    } private ObjectDataProvider _WozScreensProvider;

    public ListBox ScreensListBox
    {
      get
      {
        return _ScreensListBox;
      }
    }

    public ObservableCollection<ReplacementPad> ReplacementPads
    {
      get { return _ReplacementPads; }
      set { _ReplacementPads = value; }
    } ObservableCollection<ReplacementPad> _ReplacementPads;

    public ObjectDataProvider ReplacementPadsProvider
    {
      get { return _ReplacementPadsProvider; }
      set { _ReplacementPadsProvider = value; }
    } private ObjectDataProvider _ReplacementPadsProvider;

    public ListBox ReplacementListBox
    {
      get
      {
        return _ReplacementListBox;
      }
    }

    public ObservableCollection<ReplacementPad> UserActionReplacementPads
    {
      get { return _UserActionReplacementPads; }
      set { _UserActionReplacementPads = value; }
    } ObservableCollection<ReplacementPad> _UserActionReplacementPads;

    public ObjectDataProvider UserActionReplacementPadsProvider
    {
      get { return _UserActionReplacementPadsProvider; }
      set { _UserActionReplacementPadsProvider = value; }
    } private ObjectDataProvider _UserActionReplacementPadsProvider;

    public CollectionViewSource UserActionViewSource
    {
      get { return _UserActionViewSource; }
      set { _UserActionViewSource = value; }
    } private CollectionViewSource _UserActionViewSource;

    public ListBox UserActionReplacementListBox
    {
      get
      {
        return _UserActionReplacementListBox;
      }
    }

    private SpeechWindow _SpeechWindow;

    public SpeechWindow SpeechWindow
    {
      get { return _SpeechWindow; }
      set { _SpeechWindow = value; }
    }

    public ScratchWindow ScratchWindow
    {
      get { return _ScratchWindow; }
      set { _ScratchWindow = value; }
    } private ScratchWindow _ScratchWindow;


    // Tracking whether the wizard is currently editing a screen or if we are showing every update
    // from the client
    public bool WizardEditing
    {
      get { return _WizardEditing; }
      set { _WizardEditing = value; }
    } private bool _WizardEditing = false;
    

    // For tracking what screen is currently being viewed by the client
    public WozScreen ClientCommittedScreen
    {
      get { return _ClientCommittedScreen; }
      set { _ClientCommittedScreen = value; }
    } private WozScreen _ClientCommittedScreen = null;
    

    public bool AutoCommit
    {
      get { return _AutoCommit; }
      set { _AutoCommit = value; }
    } private bool _AutoCommit;


    public bool RealtimeCommit
    {
      get { return _RealtimeCommit; }
      set { _RealtimeCommit = value; }
    } private bool _RealtimeCommit;

    public Queue<SketchCommandCollection> ClientChangeCommandQueue
    {
      get { return _ClientChangeCommandQueue; }
      set { _ClientChangeCommandQueue = value; }
    } private Queue<SketchCommandCollection> _ClientChangeCommandQueue = new Queue<SketchCommandCollection>();

    public WizardWindow()
    {
      ServerObjectRegistry.RegisterObject(this);

      // setup client radar view
      ClientRadarCanvas = new ClientInkCanvas();
      _ClientRadarSketchObjectRegistry = new SketchObjectRegistry();
      ClientRadarCanvas.SketchObjectRegistry = _ClientRadarSketchObjectRegistry;

      // Set references for executing ClientCommands on the radar view
      _ClientRadarCommandReferences = new SketchCommandReferences();
      _ClientRadarCommandReferences.InkCanvas = ClientRadarCanvas;
      _ClientRadarCommandReferences.ClientWindow = new WozLib.UI.Containers.WozSizeable(ClientRadarCanvas, null);
      //_ClientRadarCommandReferences.InkOverlayCanvas = ClientRadarCanvas;
      _ClientRadarCommandReferences.WozObjectRegistry = _ClientRadarSketchObjectRegistry;

      this.PreviewKeyDown += new KeyEventHandler(WizardWindow_PreviewKeyDown);

      // should really be done statically
      DiscardChangesCommand = new RoutedCommand("DiscardChangesCommand", typeof(WizardWindow));
      MaximizeRectGeometry = new RoutedCommand("MaximizeRectGeometry", typeof(WizardWindow));
      MoveBackwardCommand = new RoutedCommand("MoveBackwardCommand", typeof(WizardWindow));
      MoveForwardCommand = new RoutedCommand("MoveForewardCommand", typeof(WizardWindow));
      OpenFromImagesCommand = new RoutedCommand("OpenFromImagesCommand", typeof(WizardWindow));

      CommandBinding DiscardChangesCommandCommandBinding = new CommandBinding(DiscardChangesCommand);
      DiscardChangesCommandCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(DiscardChangesCommandCommandBinding_CanExecute);
      DiscardChangesCommandCommandBinding.Executed += new ExecutedRoutedEventHandler(DiscardChangesCommandCommandBinding_Executed);
      CommandBindings.Add(DiscardChangesCommandCommandBinding);

      CommandBinding MaximizeRectGeometryCommandBinding = new CommandBinding(MaximizeRectGeometry);
      MaximizeRectGeometryCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(MaximizeRectGeometryCommandBinding_CanExecute);
      MaximizeRectGeometryCommandBinding.Executed += new ExecutedRoutedEventHandler(MaximizeRectGeometryCommandBinding_Executed);
      CommandBindings.Add(MaximizeRectGeometryCommandBinding);

      CommandBinding MoveBackwardCommandCommandBinding = new CommandBinding(MoveBackwardCommand);
      MoveBackwardCommandCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(MoveBackwardCommandCommandBinding_CanExecute);
      MoveBackwardCommandCommandBinding.Executed += new ExecutedRoutedEventHandler(MoveBackwardCommandCommandBinding_Executed);
      CommandBindings.Add(MoveBackwardCommandCommandBinding);

      CommandBinding MoveForewardCommandCommandBinding = new CommandBinding(MoveForwardCommand);
      MoveForewardCommandCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(MoveBackwardCommandCommandBinding_CanExecute);
      MoveForewardCommandCommandBinding.Executed += new ExecutedRoutedEventHandler(MoveForewardCommandCommandBinding_Executed);
      CommandBindings.Add(MoveForewardCommandCommandBinding);

      CommandBinding OpenFromImagesCommandCommandBinding = new CommandBinding(OpenFromImagesCommand);
      OpenFromImagesCommandCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(CanExecute_True);
      OpenFromImagesCommandCommandBinding.Executed += new ExecutedRoutedEventHandler(OpenFromImagesCommandCommandBinding_Executed);
      CommandBindings.Add(OpenFromImagesCommandCommandBinding);

      WozScreens = new WozScreenCollection();
      WozScreensProvider = new ObjectDataProvider();
      WozScreensProvider.ObjectInstance = WozScreens;

      ReplacementPads = new ObservableCollection<ReplacementPad>();
      ReplacementPadsProvider = new ObjectDataProvider();
      ReplacementPadsProvider.ObjectInstance = ReplacementPads;
      ReplacementPads.Add(new ReplacementPad());

      UserActionReplacementPads = new ObservableCollection<ReplacementPad>();
      UserActionReplacementPadsProvider = new ObjectDataProvider();
      UserActionReplacementPadsProvider.ObjectInstance = UserActionReplacementPads;

      UserActionViewSource = new CollectionViewSource();
      UserActionViewSource.Source = UserActionReplacementPads;
      UserActionViewSource.SortDescriptions.Add(
        new System.ComponentModel.SortDescription("ServerID", System.ComponentModel.ListSortDirection.Descending));
      SketchPad.GestureOccured += new SketchPad.GestureOccuredDelegate(SketchPad_GestureOccured);

      WozScreen wozScreen1 = new WozScreen();
      ServerObjectRegistry.RegisterObject(wozScreen1);
      wozScreen1.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
      wozScreen1.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
      wozScreen1.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
      wozScreen1.ReplacementPasteOccured += new SketchPad.ReplacementPasteOccuredDelegate(wozScreen_ReplacementPasteOccured);
      WozScreens.Add(wozScreen1);

      InitializeComponent();

      // a WozServerCommandReferences with the WizardWindow set to this to be used in
      // all WozServerCommands that only need a WizardWindow reference
      //_GenericWozServerCommandReferences = new WozServerCommandReferences(this);

      // Don't touch any interface components until WizardWindow_Loaded()
      this.Loaded += new RoutedEventHandler(WizardWindow_Loaded);
      this.Closed += new EventHandler(WizardWindow_Closed);

      // Command Bindings
      CommandBinding SaveAsCommandBinding = new CommandBinding(ApplicationCommands.SaveAs);
      SaveAsCommandBinding.Executed += new ExecutedRoutedEventHandler(SaveAsCommandBinding_Executed);
      SaveAsCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(CanExecute_True);
      CommandBindings.Add(SaveAsCommandBinding);

      CommandBinding OpenFileCommandBinding = new CommandBinding(ApplicationCommands.Open);
      OpenFileCommandBinding.Executed += new ExecutedRoutedEventHandler(OpenFileCommandBinding_Executed);
      OpenFileCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(CanExecute_True);
      CommandBindings.Add(OpenFileCommandBinding);

      CommandBinding UndoCommandBinding = new CommandBinding(ApplicationCommands.Undo);
      UndoCommandBinding.Executed += new ExecutedRoutedEventHandler(UndoCommandBinding_Executed);
      UndoCommandBinding.PreviewExecuted += new ExecutedRoutedEventHandler(UndoCommandBinding_PreviewExecuted);
      UndoCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(UndoCommandBinding_CanExecute);
      CommandBindings.Add(UndoCommandBinding);

      CommandBinding RedoCommandBinding = new CommandBinding(ApplicationCommands.Redo);
      RedoCommandBinding.Executed += new ExecutedRoutedEventHandler(RedoCommandBinding_Executed);
      RedoCommandBinding.PreviewExecuted += new ExecutedRoutedEventHandler(RedoCommandBinding_PreviewExecuted);
      RedoCommandBinding.CanExecute += new CanExecuteRoutedEventHandler(RedoCommandBinding_CanExecute);
      CommandBindings.Add(RedoCommandBinding);

    }

    /// <summary>
    /// HACK HACK HACK HACK HACK HACK HACK HACK
    /// </summary>
    /// <param name="stroke"></param>
    void SketchPad_GestureOccured(SketchStroke stroke)
    {
      ReplacementPad replacementPad = new ReplacementPad((StrokeSketchObject)stroke.GetWozObject());

      foreach (ReplacementPad pad in UserActionReplacementPads)
      {
        //pad.Opacity -= (pad.Opacity * 0.40);
      }

      UserActionReplacementPads.Add(replacementPad);
    }

    

    void AddReplacementPadFromClipboardButton_Click(object sender, RoutedEventArgs e)
    {
      // create a new replacement pad from the clipboard and add it to the list
      ReplacementPads.Add(new ReplacementPad(true));
    }

    void ReplacementPadButton_Click(object sender, RoutedEventArgs e)
    {
      // do a replacement!
      
      // get a handle on our replacment pad source
      if (sender is Button && (sender as Button).Tag is ReplacementPad &&
        ScreensListBox.SelectedItem is SketchPad)
      {        
        SketchPad sketchPad = ScreensListBox.SelectedItem as SketchPad;
        // instantiate a ReplaceSketchCommand
        ReplacementSketchCommand replacementSketchCommand = new ReplacementSketchCommand(
          (sender as Button).Tag as ReplacementPad, sketchPad, sketchPad.SelectedWozObjects);

        // set the references
        SketchCommandReferences sketchCommandReferences = new SketchCommandReferences();
        sketchCommandReferences.InkCanvas = sketchPad;
        sketchCommandReferences.WozObjectRegistry = sketchPad.WozObjectRegistry;
        replacementSketchCommand.WozClientCommandReferences = sketchCommandReferences;

        // redo it
        replacementSketchCommand.Redo();

        // log it & send to client
        sketchPad.NotifyCommandOccured(replacementSketchCommand);
      }
    }

    // this should really be in the WozObjectContainer
    void MoveForewardCommandCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      if (_ScreensListBox != null && _ScreensListBox.SelectedItem != null &&
        _ScreensListBox.SelectedItem is SketchPad)
      {
        SketchPad woc = _ScreensListBox.SelectedItem as SketchPad;

        List<SketchObject> wozObjectOrder = new List<SketchObject>(woc.VisibleWozObjects);
        List<SketchObject> selectedWozObjects = new List<SketchObject>(woc.SelectedWozObjects);

        MoveForewardSketchCommand wcmfc = 
          new MoveForewardSketchCommand(selectedWozObjects, wozObjectOrder);

        SketchCommandReferences wccr = new SketchCommandReferences();
        wccr.InkCanvas = woc;
        wccr.WozObjectRegistry = woc.WozObjectRegistry;

        wcmfc.WozClientCommandReferences = wccr;

        wcmfc.Redo();

        woc.NotifyCommandOccured(wcmfc);

        // NOT THREAD SAFE
        //for (int i = woc.Children.Count - 2; i >= 0; i--)
        //{
        //  if (selectedUies.Contains(woc.Children[i]))
        //  {
        //    UIElement toMove = woc.Children[i];
        //    woc.Children.RemoveAt(i);
        //    woc.Children.Insert(i + 1, toMove);
        //  }
        //}

        //for (int i = woc.Strokes.Count - 2; i >= 0; i--)
        //{
        //  if (selectedStrokes.Contains(woc.Strokes[i]))
        //  {
        //    Stroke toMove = woc.Strokes[i];
        //    woc.Strokes.RemoveAt(i);
        //    woc.Strokes.Insert(i + 1, toMove);
        //  }
        //}

        //woc.Select(selectedStrokes, selectedUies);        

      }
    }

    void MoveBackwardCommandCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      if (_ScreensListBox != null && _ScreensListBox.SelectedItem != null &&
        _ScreensListBox.SelectedItem is SketchPad)
      {
        SketchPad woc = _ScreensListBox.SelectedItem as SketchPad;

        List<SketchObject> wozObjectOrder = new List<SketchObject>(woc.VisibleWozObjects);
        List<SketchObject> selectedWozObjects = new List<SketchObject>(woc.SelectedWozObjects);

        MoveBackwardSketchCommand wcmbc =
          new MoveBackwardSketchCommand(selectedWozObjects, wozObjectOrder);

        SketchCommandReferences wccr = new SketchCommandReferences();
        wccr.InkCanvas = woc;
        wccr.WozObjectRegistry = woc.WozObjectRegistry;

        wcmbc.WozClientCommandReferences = wccr;

        wcmbc.Redo();

        woc.NotifyCommandOccured(wcmbc);

        //WozObjectContainer woc = _ScreensListBox.SelectedItem as WozObjectContainer;
        //List<UIElement> selectedUies = new List<UIElement>(woc.GetSelectedElements());
        //StrokeCollection selectedStrokes = new StrokeCollection(woc.GetSelectedStrokes());

        //// NOT THREAD SAFE
        //for (int i = 1; i < woc.Children.Count; i++)
        //{
        //  if (selectedUies.Contains(woc.Children[i]))
        //  {
        //    UIElement toMove = woc.Children[i];
        //    woc.Children.RemoveAt(i);
        //    woc.Children.Insert(i - 1, toMove);
        //  }
        //}

        //for (int i = 1; i < woc.Strokes.Count; i++)
        //{
        //  if (selectedStrokes.Contains(woc.Strokes[i]))
        //  {
        //    Stroke toMove = woc.Strokes[i];
        //    woc.Strokes.RemoveAt(i);
        //    woc.Strokes.Insert(i - 1, toMove);
        //  }
        //}

        //woc.Select(selectedStrokes, selectedUies);

      }
    }

    void MoveBackwardCommandCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      if (_ScreensListBox != null && _ScreensListBox.SelectedItem != null &&
        _ScreensListBox.SelectedItem is SketchPad &&
        ((_ScreensListBox.SelectedItem as SketchPad).GetSelectedElements().Count > 0 ||
        (_ScreensListBox.SelectedItem as SketchPad).GetSelectedStrokes().Count > 0))
      {
        e.CanExecute = true;
      }
    }

    /// <summary>
    /// Just a little hack to make it so that the SelectionTool is selected when F2 is pressed.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void WizardWindow_PreviewKeyDown(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.F2)
      {
        WozLib.WozCommands.SelectToolWozCommand wozSelectToolCommand = new WozLib.WozCommands.SelectToolWozCommand(SketchPad.CurrentInkTool, SketchPad.InkTools.Selector);
        wozSelectToolCommand.Redo();
        WozServerCommandOccured(wozSelectToolCommand);
      }
    }

    void MaximizeRectGeometryCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      if (e.Parameter is RectGeometryCascadingProperty && _ScreensListBox.SelectedItem is WozScreen)
      {
        WozScreen wozScreen = _ScreensListBox.SelectedItem as WozScreen;
        RectGeometryCascadingProperty wgcp = e.Parameter as RectGeometryCascadingProperty;
        wgcp.RectGeometryWozProperty.Rect = new Rect(0.0, 0.0, wozScreen.Width, wozScreen.Height);
      }
    }

    void MaximizeRectGeometryCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = true;
    }

    void OpenFileCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      LoadWorkspaceFromFile();
    }

    void OpenFromImagesCommandCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      AddScreensFromImages();
    }

    void SaveAsCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      SaveWorkSpaceToFile();
    }

    

    void CanExecute_True(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = true;
    }

    

    void DiscardChangesCommandCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      DiscardChanges();
    }

    private void DiscardChanges()
    {
      if (_ScreensListBox.SelectedItem != null && _ScreensListBox.SelectedItem is SketchPad)
      {
        SketchPad woc = _ScreensListBox.SelectedItem as SketchPad;
        bool isClientCommittedScreen = (woc == ClientCommittedScreen);

        // create a new discard changes server command and redo it
        WozDiscardChangesCommand wozDiscardChangesCommand = new WozDiscardChangesCommand(this, woc.ServerID,isClientCommittedScreen);
        //wozDiscardChangesCommand.WozServerCommandReferences = this._GenericWozServerCommandReferences;
        wozDiscardChangesCommand.Redo();

        WozServerCommandOccured(wozDiscardChangesCommand);

        // to be able to undo this command we need to save the state of the 
        // (_ScreensListBox.SelectedItem as WozObjectContainer).SinceCommitServerCommandStack

        // if we are NOT in auto-commit then also save state of ClientChangeCommandQueue
        // if (_ScreensListBox.SelectedItem == _ClientCommittedScreen)
        // then we have to redo/undo applying the ClientChangeCommandQueue
      }
    }

    void DiscardChangesCommandCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      if (_ScreensListBox != null && _ScreensListBox.SelectedItem != null && _ScreensListBox.SelectedItem is SketchPad)
      {
        SketchPad woc = _ScreensListBox.SelectedItem as SketchPad;
        if (woc.SinceCommitServerCommandStack != null && woc.SinceCommitServerCommandStack.Count > 0)
        {
          e.CanExecute = true;
        }
      }
    }

    void wozScreen_ContinuousCommandOccured(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      // if autocommit send it
      if (
        (wozServerCommand is WozLib.WozCommands.ClientWozCommand ||
         (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand &&
         (wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand is WozLib.WozCommands.ClientWozCommand))
        && AutoCommit)
      {
        if (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand)
        {
          SendClientCommand(((wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand as ClientWozCommand).WozClientCommands);
        }
        else if (wozServerCommand is WozLib.WozCommands.ClientWozCommand)
        {
          SendClientCommand((wozServerCommand as WozLib.WozCommands.ClientWozCommand).WozClientCommands);
        }

      }
    }

    void wozScreen_CommandOccuredNoUndoRedo(WozCommand wozServerCommand)
    {
      ////hack
      if (wozServerCommand is WozLib.WozCommands.SelectToolWozCommand)
      {
        wozServerCommand.Redo();
      }

      // we automatically send these REGARDLESS OF AUTOCOMMIT MODE!!!!
      // if client command or sketch command
      if (
        (wozServerCommand is WozLib.WozCommands.ClientWozCommand ||
         (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand &&
         (wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand is WozLib.WozCommands.ClientWozCommand)))
      {
        if (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand)
        {
          SendClientCommand(((wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand as ClientWozCommand).WozClientCommands);
        }
        else if (wozServerCommand is WozLib.WozCommands.ClientWozCommand)
        {
          SendClientCommand((wozServerCommand as WozLib.WozCommands.ClientWozCommand).WozClientCommands);
        }
      }

      WozServerCommandOccuredNoUndo(wozServerCommand);
    }

    void WozScreen_CommandOccured(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      //wozServerCommand.WozServerCommandReferences = _GenericWozServerCommandReferences;

      ////hack
      if (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand &&
         (wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand is WozLib.WozCommands.SelectToolWozCommand)
      {
        wozServerCommand.Redo();
      }

      // if autocommit send it
      if (
        (wozServerCommand is WozLib.WozCommands.ClientWozCommand ||
         (wozServerCommand is WozLib.WozCommands.SketchPadWozCommand &&
         (wozServerCommand as WozLib.WozCommands.SketchPadWozCommand).WozServerCommand is WozLib.WozCommands.ClientWozCommand))
        && AutoCommit)
      {
        //if (wozServerCommand is WozObjectContainerServerCommand)
        //{
        //  SendClientCommand(((wozServerCommand as WozObjectContainerServerCommand).WozServerCommand as WozServerClientCommand).WozClientCommands);
        //}
        //else if (wozServerCommand is WozServerClientCommand)
        //{
        //  SendClientCommand((wozServerCommand as WozServerClientCommand).WozClientCommands);
        //}

        // wrap this in a WozServerClientSendCommand
        WozServerClientSendCommand wozServerClientSendCommand = new WozServerClientSendCommand(this, wozServerCommand, true);
        WozServerCommandOccured(wozServerClientSendCommand);
      }
      else
      {
        // if we are not in autocommit then we don't log this as a WozServerCommand
        WozServerCommandOccured(wozServerCommand);
      }
    }

    

    void RedoCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = _RedoStack.Count > 0;
    }

    void RedoCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      Redo();
    }

    // trying to fix textbox screwing up undo/redo
    void RedoCommandBinding_PreviewExecuted(object sender, ExecutedRoutedEventArgs e)
    {
      RedoCommandBinding_Executed(sender, e);
    }

    void UndoCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = _UndoStack.Count > 0;
    }

    void UndoCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      Undo();
    }

    // trying to fix textbox screwing up undo/redo
    void UndoCommandBinding_PreviewExecuted(object sender, ExecutedRoutedEventArgs e)
    {
      UndoCommandBinding_Executed(sender, e);
    }

    void WizardWindow_Closed(object sender, EventArgs e)
    {
      _WozServer.Stop();
      _HttpFileServer.Stop();
      //_ImageServerThread.Interrupt();
      _FileServerThread.Abort();
      //_ClientMirrowWindow.Close();
      if (SpeechWindow != null)
      {
        SpeechWindow.Close();
      }
      if (ScratchWindow != null)
      {
        ScratchWindow.Close();
      }
    }

    void WizardWindow_Loaded(object sender, RoutedEventArgs e)
    {
      ClientRadarCanvas.UIElementToAdorn = _ClientRadarGrid;

      _ToolSelectToolbar.WozServerCommandOccured += new WozLib.UI.Controls.ToolSelectToolbar.WozServerCommandOccuredDelegate(_ToolSelectToolbar_WozServerCommandOccured);

      _ScreensListBox.SelectionChanged += new SelectionChangedEventHandler(_ScreensListBox_SelectionChanged);
      _ScreensListBox.ItemsReordered += new RoutedEventHandler(_ScreensListBox_ItemsReordered);
      //_ScreensListBox2.ItemsReordered += new RoutedEventHandler(_ScreensListBox_ItemsReordered);
      

      //_ClientMirrowWindow = new ClientMirrorWindow();

      // Commented out until this gets fixed to be accurate
      //_ClientMirrowWindow.Show();

      _ClientMirrorWozObjectRegistry.ServerMode = true;

      _ClientMirrorCommandReferences = new SketchCommandReferences();

      //_ClientMirrorCommandReferences.InkCanvas = _ClientMirrowWindow.ClientInkCanvas;
      //_ClientMirrorCommandReferences.ClientWindow = new WozLib.UI.Containers.WozSizeable(_ClientMirrowWindow);
      //_ClientMirrorCommandReferences.InkOverlayCanvas = _ClientMirrowWindow.InkOverlayCanvas;
      //_ClientMirrorCommandReferences.WozObjectRegistry = _ClientMirrorWozObjectRegistry;

      //_ClientMirrowWindow.ClientInkCanvas.CommandOccured += new WozLib.UI.Ink.ClientInkCanvas.CommandOccuredDelegate(ClientInkCanvas_CommandOccured);
      //_ClientMirrowWindow.ClientInkCanvas.WozObjectRegistry = _ClientMirrorWozObjectRegistry;

      RealTimeCheck.Checked += new RoutedEventHandler(RealTimeCheck_Checked);
      RealTimeCheck.Unchecked += new RoutedEventHandler(RealTimeCheck_Unchecked);
      AutoCommitCheck.Checked += new RoutedEventHandler(AutoCommitCheck_Checked);
      AutoCommitCheck.Unchecked += new RoutedEventHandler(AutoCommitCheck_Unchecked);

      CommitButton.Click += new RoutedEventHandler(CommitButton_Click);
      DiscardButton.Click += new RoutedEventHandler(DiscardButton_Click);

      // should really use a routed command for this
      _AddScreenButton.Click += new RoutedEventHandler(_AddScreenButton_Click);
      _AddScreenButton2.Click += new RoutedEventHandler(_AddScreenButton_Click);

      // setup state for committing screens
      if (_ScreensListBox.SelectedItem is WozScreen)
      {
        _ClientCommittedScreen = _ScreensListBox.SelectedItem as WozScreen;
        _ClientCommittedScreen.InOverlayMode = true;
        //this.WizardEditing = false;
      }

      _SelectedScreenContentControl.PreviewMouseDown += new MouseButtonEventHandler(_SelectedScreenContentControl_PreviewMouseDown);     

      // got to setup the image server

      _HttpFileServer = new HttpFileServer(WozServer.HTTP_FILE_SERVER_PORT);
      _FileServerThread = new Thread(new ThreadStart(_HttpFileServer.Listen));
      _FileServerThread.Start();

      // Setting up the network server should be the last thing we do
      _WozServer = new WozServer();

      _WozServer.WozClientCommandsReceived += new WozServer.WozClientCommandsReceivedDelegate(_WozServer_WozClientCommandsReceived);
      _WozServer.Connected += new WozServer.ConnectedDelegate(_WozServer_ConnectedAsync);

      _WozServer.Start();

      this.Title += " (" + _WozServer.AddrString + ")";

      this.SpeechWindow = new SpeechWindow();
      SpeechWindow.CommandOccured += new SpeechWindow.CommandOccuredDelegate(SpeechWindow_CommandOccured);
      SpeechWindow.Show();

      ScratchWindow = new ScratchWindow();
      ScratchWindow.Closed += new EventHandler(ScratchWindow_Closed);
      ScratchWindow.Show();
      _ShowScratchPadButton.Click += new RoutedEventHandler(_ShowScratchPadButton_Click);

      // set autocommit mode
      this.AutoCommitCheck.IsChecked = true;

      _AutoSaveTimer = new System.Timers.Timer();
      _AutoSaveTimer.AutoReset = false;
      _AutoSaveTimer.Interval = _AutoSaveFileIntervalMS;
      _AutoSaveTimer.Elapsed += new System.Timers.ElapsedEventHandler(_AutoSaveTimer_Elapsed);
      _AutoSaveTimer.Start();
    }

    

    void ScratchWindow_Closed(object sender, EventArgs e)
    {
      if (ScratchWindow != null)
      {
        ScratchWindow.Closed -= new EventHandler(ScratchWindow_Closed);
        ScratchWindow = null;
      }
    }

    void _ShowScratchPadButton_Click(object sender, RoutedEventArgs e)
    {
      if (ScratchWindow != null)
      {
        ScratchWindow.Activate();
      }
      else
      {
        ScratchWindow = new ScratchWindow();
        ScratchWindow.Closed += new EventHandler(ScratchWindow_Closed);
        ScratchWindow.Show();
      }
    }

    void _ToolSelectToolbar_WozServerCommandOccured(WozCommand wozServerCommand)
    {
      WozServerCommandOccured(wozServerCommand);
    }

    /// <summary>
    /// Occurs when a client connects to us. We respond by sending our current 
    /// screen. Otherwise known as doing a commit.
    /// This is done on the dispatcher.
    /// </summary>
    void _WozServer_ConnectedAsync()
    {
      this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new WozServer_Connected_Delgate(_WozServer_ConnectedSync));
    }

    /// <summary>
    /// Used for invoking _WozServer_ConnectedSync on the dispatcher
    /// </summary>
    private delegate void WozServer_Connected_Delgate();

    /// <summary>
    /// Occurs when a client connects to us. We respond by sending our current 
    /// screen. Otherwise known as doing a commit.
    /// This method should always be called on the dispatcher thread for this window.
    /// </summary>
    void _WozServer_ConnectedSync()
    {
      Commit();
    }

    void _ScreensListBox_ItemsReordered(object sender, RoutedEventArgs e)
    {
      try
      {
        int selectedIndex = _ScreensListBox.SelectedIndex;
        ((WozScreenCollection)_ScreensListBox.ItemsSource).Move(_ScreensListBox.OriginalItemIndex, selectedIndex);
        _ScreensListBox.SelectedIndex = selectedIndex;
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }
    }

    void SpeechWindow_CommandOccured(SketchCommand wozClientCommand)
    {
      SendClientCommand(wozClientCommand);
    }

    private void AddScreensFromImages()
    {
      try
      {
        // ask the user for an .xml file to load up
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Title = "Select the images you would like to make screens from.";
        openFileDialog.Filter = "Image Files(*.BMP;*.JPG;*.JPEG;*.GIF;*.PNG)|*.BMP;*.JPG;*.JPEG;*.GIF;*.PNG|All files (*.*)|*.*";
        openFileDialog.Multiselect = true;

        int newScreenCount = 0;
        if (openFileDialog.ShowDialog() == true)
        {
          foreach (string filename in openFileDialog.FileNames)
          {
            try
            {
              // create a new screen with the name of the files and maximize an image as the only SketchObject
              int lastSlash = filename.LastIndexOf(@"\") + 1;
              string screenName = filename.Substring(lastSlash);
              if (screenName == null || screenName.Equals(""))
              {
                screenName = "untitled" + newScreenCount;
              }

              WozScreen wozScreen = new WozScreen();
              ServerObjectRegistry.RegisterObject(wozScreen);

              // give it the filename as the screen name
              wozScreen.Description = screenName;

              // see if we can give it a smart width and height
              if (this.WozScreens.Count > 0)
              {
                wozScreen.Width = this.WozScreens[0].Width;
                wozScreen.Height = this.WozScreens[0].Height;
              }

              // add it to our screens
              this.WozScreens.Add(wozScreen);

              // add image
              // register the local file to be served
              HttpFileServer.RegisterFile(filename);

              // maximize the image
              Rect imageRect = new Rect(new Size(wozScreen.Width, wozScreen.Height));

              SketchRectangle wozRectangle = new SketchRectangle(imageRect, wozScreen.WozObjectRegistry, filename);
              wozScreen.Children.Add(wozRectangle);

              // register events we are interested in
              wozScreen.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
              wozScreen.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
              wozScreen.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
              wozScreen.ReplacementPasteOccured += new SketchPad.ReplacementPasteOccuredDelegate(wozScreen_ReplacementPasteOccured);

              newScreenCount++;
            }
            catch (Exception ex)
            {
              Debug.WriteLine(ex.ToString());
            }
          }
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }
    }

    

    private void LoadWorkspaceFromFile()
    {
      try
      {
        // ask the user for an .xml file to load up
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Title = "Where do you want to load the Wizard Workspace from?";
        openFileDialog.Filter = "XML|*.xml";

        // $tss We need to make sure the server and client registries don't have collisions with these new items

        if (openFileDialog.ShowDialog() == true)
        {
          // must clear out the registry before we do any deserializing because otherwise objects that are
          // being deserialized will get confused
          WozScreens.Clear();
          ReplacementPads.Clear();
          ServerObjectRegistry.Clear();
          if (ScratchWindow != null)
          {
            ScratchWindow.WozScreens.Clear();
          }

          // Insert code to set properties and fields of the object.
          XmlSerializer mySerializer = new XmlSerializer(typeof(List<ServerObject>), _WizardWindowWozObjectTypes);

          //XmlSerializer xm = new XmlSerializer(

          StreamReader sr = new StreamReader(openFileDialog.FileName);

          List<ServerObject> unserialized = (List<ServerObject>)mySerializer.Deserialize(sr);

          sr.Close();

          foreach (ServerObject serverObject in unserialized)
          {
            if (serverObject is ReplacementPadServerObject)
            {
              ReplacementPadServerObject replacementPadServerObject = serverObject as ReplacementPadServerObject;
              ReplacementPad replacementPad = replacementPadServerObject.GetIServerObject() as ReplacementPad;
              ReplacementPads.Add(replacementPad);
            }
            else if (serverObject is ScreenServerObject)
            {
              ScreenServerObject screenServerObject = serverObject as ScreenServerObject;
              WozScreen wozScreen = screenServerObject.GetIServerObject() as WozScreen;
              // Don't need to register it because the factory will take care of it
              //ServerObjectRegistry.RegisterObjectWithExisitingId(wozScreen);
              wozScreen.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
              wozScreen.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
              wozScreen.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
              wozScreen.ReplacementPasteOccured += new SketchPad.ReplacementPasteOccuredDelegate(wozScreen_ReplacementPasteOccured);
              WozScreens.Add(wozScreen);
            }
            else if (serverObject is ScratchWindowWozObject)
            {
              ScratchWindowWozObject scratchWindowWozObject = serverObject as ScratchWindowWozObject;

              // assume there will only be one ScratchWindow
              // we are already instantiated so just assign our ServerID
              if (ScratchWindow != null)
              {
                this.ScratchWindow.ServerID = serverObject.ServerID;
                ServerObjectRegistry.RegisterObjectWithExisitingId(this.ScratchWindow);
              }

              foreach (ScreenServerObject screenServerObject in scratchWindowWozObject.WozScreens)
              {
                IServerObject iServerObject = screenServerObject.GetIServerObject();
                if (iServerObject is WozScreen && ScratchWindow != null)
                {
                  WozScreen wozScreen = iServerObject as WozScreen;
                  this.ScratchWindow.AddWozScreen(wozScreen);
                }
              }
            }
            else if (serverObject is StringToSpeakServerObject)
            {
              if (SpeechWindow != null && SpeechWindow.AudioPromptCollection != null)
              {
                StringToSpeakServerObject stso = serverObject as StringToSpeakServerObject;
                StringToSpeak sts = stso.GetIServerObject() as StringToSpeak;
                SpeechWindow.AudioPromptCollection.Add(sts);
              }
            }
            else if (serverObject is AudioToPlayServerObject)
            {
              if (SpeechWindow != null && SpeechWindow.AudioPromptCollection != null)
              {
                AudioToPlayServerObject atpso = serverObject as AudioToPlayServerObject;
                AudioToPlay ata = atpso.GetIServerObject() as AudioToPlay;
                SpeechWindow.AudioPromptCollection.Add(ata);
              }
            }
            else if (serverObject is WizardWindowWozObject)
            {
              // assume there will only be one WizardWindow
              // we are already instantiated so just assign our ServerID
              this.ServerID = serverObject.ServerID;
              ServerObjectRegistry.RegisterObjectWithExisitingId(this);
            }
          }

          // select the first WozScreen
          if (_ScreensListBox.Items.Count > 0)
          {
            _ScreensListBox.SelectedIndex = 0;
          }
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }
    }

    private void SaveWorkSpaceToFile()
    {
      try
      {
        // ask the user where to save the file
        SaveFileDialog saveFileDialog = new SaveFileDialog();
        saveFileDialog.Title = "Where do you want to save the Wizard Workspace?";
        saveFileDialog.Filter = "XML|*.xml";

        if (saveFileDialog.ShowDialog() == true)
        {
          // save it out

          SaveWorkSpaceToFile(saveFileDialog.FileName);
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }
      
    }

    System.Timers.Timer _AutoSaveTimer;
    int _AutoSaveFileNumber = 0;
    const int _AutoSaveFileNumberMax = 10;
    // save every minute
    const long _AutoSaveFileIntervalMS = 60000;
    delegate void SaveWorkSpaceToFileSyncDelegate();

    void _AutoSaveTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
      this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle,
        new SaveWorkSpaceToFileSyncDelegate(SaveWorkSpaceToFileSync));
    }

    private void SaveWorkSpaceToFileSync()
    {
      if (_AutoSaveFileNumber < _AutoSaveFileNumberMax)
      {
        _AutoSaveFileNumber++;
      }
      else
      {
        _AutoSaveFileNumber = 0;
      }

      if (!Directory.Exists(@"C:\SketchWizard\"))
      {
        Directory.CreateDirectory(@"C:\SketchWizard\");
      }

      string filename = @"C:\SketchWizard\SketchWizard_AutoSave_" + _AutoSaveFileNumber + ".xml";

      SaveWorkSpaceToFile(filename);
      Debug.WriteLine("Auto Saved: " + filename);
      if (_AutoSaveTimer != null)
      {
        _AutoSaveTimer.Start();
      }
    }

    private void SaveWorkSpaceToFile(string filename)
    {
      try
      {
        // save it out

        // objects to save
        List<ServerObject> wozObjects = new List<ServerObject>();

        // save the wizardwindow
        // eventually this should really be the only command
        // when all the data is embedded in a single WizardWorkspace business object
        wozObjects.Add(this.GetServerObject());

        // WozScreens
        foreach (WozScreen wozScreen in WozScreens)
        {
          wozObjects.Add(wozScreen.GetServerObject());
        }

        // ScratchPads
        // these screens can't be in the same bin because they'll get confused with the main screens
        if (this.ScratchWindow != null)
        {
          wozObjects.Add(this.ScratchWindow.GetServerObject());
        }

        // ReplacementPads
        foreach (ReplacementPad replacementPad in ReplacementPads)
        {
          wozObjects.Add(replacementPad.GetServerObject());
        }

        //StringToSpeaks
        if (SpeechWindow != null && SpeechWindow.AudioPromptCollection != null)
        {
          foreach (AudioPrompt audioPrompt in SpeechWindow.AudioPromptCollection)
          {
            wozObjects.Add(audioPrompt.GetServerObject());
          }
        }

        // Insert code to set properties and fields of the object.
        XmlSerializer mySerializer = new XmlSerializer(typeof(List<ServerObject>), _WizardWindowWozObjectTypes);

        // To write to a file, create a StreamWriter object.
        StreamWriter sw = new StreamWriter(filename);
        mySerializer.Serialize(sw, wozObjects);
        sw.Close();
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.ToString());
      }

    }

    void DiscardButton_Click(object sender, RoutedEventArgs e)
    {
      // todo
      // figure this out later
    }

    /// <summary>
    /// occurs when the user click on the commit changes button in the UI.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void CommitButton_Click(object sender, RoutedEventArgs e)
    {
      Commit();
    }

    /// <summary>
    /// Commits the state of the currently selected screen to the client.
    /// The client's screen will immediatly look exactly like the Wizard's screen.
    /// </summary>
    private void Commit()
    {
      //if (WizardEditing)
      //{
      //  WizardEditing = false;
      //  CommitSelectedScreen();
      //}

      //WizardEditing = false;

      WozCommitChangesCommand wccc = new WozCommitChangesCommand(this);
      //wccc.WozServerCommandReferences = _GenericWozServerCommandReferences;
      wccc.Redo();
      WozServerCommandOccured(wccc);
      //CommitSelectedScreen();

      //$$$$$HACK HACK HACK HACK HACK
      //this needs to be rolled up into WozCommitChangesCommand so that it can be undone
      //last minute hack before the paper deadline

      foreach (ReplacementPad replacementPad in UserActionReplacementPads)
      {
        //replacementPad.Opacity *= 0.5;
        replacementPad.Opacity = 0.5;
      }
    }

    //private void CommitSelectedScreen()
    //{
    //  // todo
    //  // make an undo/redo command for committing the selected screen

    //  // It's hard to know whether to push an UNDO/REDO right here
    //  // because people call us in autocommit by switching screen
    //  // while other wise it comes through an actual commit action
    //  // so we should just be rolled into other commands

    //  // if in AUTO then need to wrap this with a screenSelectionCommand

    //  // otherwise we can just push this command alone on the undo/redo stack

    //  // set the ClientCommittedScreen to the current selected screen
    //  //if (_ScreensListBox.SelectedItem is WozScreen)
    //  //{
    //  //  if (ClientCommittedScreen != _ScreensListBox.SelectedItem)
    //  //  {
    //  //    // take the old screen out of ink committed mode
    //  //    ClientCommittedScreen.InOverlayMode = false;

    //  //    // todo
    //  //    // going to need to roll up a changeing of ClientCommittedScreen into undo/redo

    //  //    // update reference
    //  //    ClientCommittedScreen = _ScreensListBox.SelectedItem as WozScreen;
    //  //  }

    //  //  // clear the change log after a commit
    //  //  _ClientChangeCommandQueue = new Queue<WozClientCommands>();
    //  //}

    //  //if (ClientCommittedScreen != null)
    //  //{
    //  //  // push the selected screen's ClientObjectRegistry over to the client

    //  //  // send clear command
    //  //  WozClientClearCommand wozClientClearCommand = new WozClientClearCommand();
    //  //  SendClientCommand(wozClientClearCommand);

    //  //  // send create command for everything visible
    //  //  List<WozObject> toAdd = new List<WozObject>();

    //  //  foreach (UIElement uie in ClientCommittedScreen.Children)
    //  //  {
    //  //    if (uie is IWozObject)
    //  //    {
    //  //      toAdd.Add((uie as IWozObject).GetWozObject());
    //  //    }
    //  //  }

    //  //  foreach (Stroke stroke in ClientCommittedScreen.Strokes)
    //  //  {
    //  //    if (stroke is IWozObject)
    //  //    {
    //  //      toAdd.Add((stroke as IWozObject).GetWozObject());
    //  //    }
    //  //  }

    //  //  WozClientCreateCommand wozClientCreateCommand = new WozClientCreateCommand(toAdd);
    //  //  SendClientCommand(wozClientCreateCommand);

    //  //  // put the selected screen into clientoverlay mode
    //  //  ClientCommittedScreen.InOverlayMode = true;
    //  //}
    //}

    private void EnterWizardEditingMode()
    {
      // if they are editing the ClientCommittedScreen, take it out of clientoverlay mode
      if (_ScreensListBox.SelectedItem == _ClientCommittedScreen)
      {
        _ClientCommittedScreen.InOverlayMode = false;

        if (ClientCommittedScreen != null && !(ClientCommittedScreen.Background is VisualBrush) && _ClientRadarCanvas != null)
        {
          //<VisualBrush Stretch="Uniform"
          //                                   Visual="{Binding ElementName=_WizardWindow, Path=ClientRadarCanvas}"
          //                                   Opacity="0.5"
          //                                   />

          Grid grid = new Grid();

          Grid grid2 = new Grid();

          VisualBrush visualBrush = new VisualBrush(_ClientRadarCanvas);
          visualBrush.Stretch = Stretch.None;
          //visualBrush.AlignmentX = AlignmentX.Left;
          visualBrush.Opacity = 0.3;

          grid2.Background = visualBrush;
          // HACK!!!!
          grid2.Width = 5000;
          grid2.Height = 5000;

          grid.Children.Add(grid2);
          grid.Background = Brushes.White;
          // HACK!!!!
          grid.Width = 5000;
          grid.Height = 5000;
          //grid.Background = Brushes.Purple;

          VisualBrush visualBrush2 = new VisualBrush(grid);
          //visualBrush.AlignmentX = AlignmentX.Left;
          visualBrush2.Stretch = Stretch.None;

          //VisualBrush visualBrush = new VisualBrush(_ClientRadarCanvas);
          //visualBrush.Stretch = Stretch.Uniform;
          //visualBrush.Opacity = 0.5;

          ClientCommittedScreen.Background = visualBrush2;
        }
      }
    }

    void ClientInkCanvas_CommandOccured(SketchCommand wozClientCommand)
    {
      //SendClientCommand(wozClientCommand);
    }

    public void SendClientCommand(SketchCommand wozClientCommand)
    {
      _WozServer.SendWozClientCommands(new SketchCommandCollection(wozClientCommand));

      //handle radar view
      ClientRadarCommands(new SketchCommandCollection(wozClientCommand));
    }

    public void SendClientCommand(SketchCommandCollection wozClientCommands)
    {
      if (_WozServer != null)
      {
        _WozServer.SendWozClientCommands(wozClientCommands);
      }

      //handle radar view
      ClientRadarCommands(wozClientCommands);
    }

    void _WozServer_WozClientCommandsReceived(SketchCommandCollection wozClientCommands)
    {
      wozClientCommands.SetCommandReferences(_ClientMirrorCommandReferences);
      RunCommands(wozClientCommands);

      // handle radar view
      this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new RunCommandsDelgate(ClientRadarCommands), wozClientCommands);
    }

    private void ClientRadarCommands(SketchCommandCollection sketchClientCommands)
    {
      SketchCommandReferences oldRefs = sketchClientCommands.GetCommandReferences();

      //ClientRadarCanvas
      sketchClientCommands.SetCommandReferences(_ClientRadarCommandReferences);
      sketchClientCommands.RedoAll();

      sketchClientCommands.SetCommandReferences(oldRefs);
    }

    public void RunCommands(SketchCommandCollection wozClientCommands)
    {
      this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new RunCommandsDelgate(RunCommandsInternal), wozClientCommands);
    }

    private delegate void RunCommandsDelgate(SketchCommandCollection wozClientCommands);

    bool _RunningClientChanges = false;
    private void RunCommandsInternal(SketchCommandCollection wozClientCommands)
    {
      // for client mirrow window
      //wozClientCommands.RedoAll();

      if (ClientCommittedScreen != null)
      {
        // we actually want to run it again using a new ClientCommandReferences

        //to get a speed up just make one of these each time the ClientCommittedScreen changes

        SketchCommandReferences screenWozClientCommandReferences = new SketchCommandReferences();
        screenWozClientCommandReferences.ClientWindow = new WozSizeable(ClientCommittedScreen);
        screenWozClientCommandReferences.InkCanvas = ClientCommittedScreen;
        screenWozClientCommandReferences.WozObjectRegistry = ClientCommittedScreen.WozObjectRegistry;
        screenWozClientCommandReferences.InkOverlayCanvas = null;

        wozClientCommands.SetCommandReferences(screenWozClientCommandReferences);

        if (ClientCommittedScreen.InOverlayMode)
        {
          // if the selected screen is in overlay mode then do it right away
          // we need to drop changes on the floor while this is happening
          _RunningClientChanges = true;
          wozClientCommands.RedoAll();
          _RunningClientChanges = false;
        }
        else
        {
          // otherwise just store them up
          _ClientChangeCommandQueue.Enqueue(wozClientCommands);
        }

        
      }

      foreach (SketchCommand sketchCommand in wozClientCommands.WozClientCommandList)
      {
        if (sketchCommand is UserButtonActionSketchCommand)
        {
          UserButtonActionSketchCommand userButtonActionSketchCommand = 
            sketchCommand as UserButtonActionSketchCommand;

          Console.WriteLine("User clicked a button!");

          ButtonSketchObject buttonSketchObject = userButtonActionSketchCommand.GetSketchButton();

          if (buttonSketchObject != null)
          {
            ReplacementPad replacementPad = new ReplacementPad(buttonSketchObject);

            foreach (ReplacementPad pad in UserActionReplacementPads)
            {
              //pad.Opacity -= (pad.Opacity * 0.40);
            }

            UserActionReplacementPads.Add(replacementPad);
          }
        }
        else if (sketchCommand is LinkActionSketchCommand)
        {

          RectangleSketchObject rectangleSketchObject = (sketchCommand as LinkActionSketchCommand).GetSketchRectangle();
          foreach (SketchProperty sketchProperty in rectangleSketchObject.WozProperties)
          {
            if (sketchProperty.WozPropertyType == WozPropertyType.LinkedScreenID)
            {
              long screenServerID = (sketchProperty as LongSketchProperty).Data;

              if (screenServerID > 0)
              {
                Console.WriteLine("User clicked a link! Navigating to screen # " + screenServerID);

                if (ScreensListBox.Items.Contains(ServerObjectRegistry.GetObject(screenServerID)))
                {
                  ScreensListBox.SelectedItem = ServerObjectRegistry.GetObject(screenServerID);
                }
              }
            }
          }
        }
      }
    }

    // we catch the preview of mouse down in the contentcontrol that the selected screen appears in
    // so we can switch to Wizard Editing mode when not in auto-commit mode
    void _SelectedScreenContentControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
      if (!AutoCommit)
      {
        //WizardEditing = true;
        EnterWizardEditingMode();
      }
    }    

    void _AddScreenButton_Click(object sender, RoutedEventArgs e)
    {
      AddScreen();
    }

    private void AddScreen()
    {
      try
      {
        double width = 1024;
        double height = 768;

        if (_ScreensListBox.Items.Count > 0 && _ScreensListBox.Items[0] is WozScreen)
        {
          width = (_ScreensListBox.Items[0] as WozScreen).Width;
          height = (_ScreensListBox.Items[0] as WozScreen).Height;
        }

        if (_ScreensListBox.SelectedItem is WozScreen)
        {
          width = (_ScreensListBox.SelectedItem as WozScreen).Width;
          height = (_ScreensListBox.SelectedItem as WozScreen).Height;
        }

        WozScreen wozScreen = new WozScreen(width,height);
        ServerObjectRegistry.RegisterObject(wozScreen);
        wozScreen.CommandOccured += new SketchPad.CommandOccuredDelegate(WozScreen_CommandOccured);
        wozScreen.CommandOccuredNoUndoRedo += new SketchPad.CommandOccuredDelegate(wozScreen_CommandOccuredNoUndoRedo);
        wozScreen.ContinuousCommandOccured += new SketchPad.CommandOccuredDelegate(wozScreen_ContinuousCommandOccured);
        wozScreen.ReplacementPasteOccured += new SketchPad.ReplacementPasteOccuredDelegate(wozScreen_ReplacementPasteOccured);
        WozScreens.Add(wozScreen);
        _ScreensListBox.SelectedItem = wozScreen;
        _ScreensListBox.ScrollIntoView(wozScreen);
        _ScreensListBox2.ScrollIntoView(wozScreen);
      }
      catch (Exception ex)
      {
        Debug.WriteLine("Add new screen failed: " + ex.ToString());
      }
    }

    void wozScreen_ReplacementPasteOccured(ReplacementPad newReplacementPad)
    {
      ReplacementPads.Add(newReplacementPad);
    }

    /// <summary>
    /// if the calling textbox is not focused, this method focuses the textbox
    /// and selects all the text. One would use this method as the PreviewMouseDown
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is clicked once.
    /// 
    /// We cannot use GotFocus because the click handler will unselect the text and
    /// place the cursor at the click point
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void _TextBox_SelectAll_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
      // if it was a textbox that was clicked and its not selected
      if (sender is TextBox && !(sender as TextBox).IsFocused)
      {
        // select all the text
        (sender as TextBox).SelectAll();

        // give the textbox input focus
        (sender as TextBox).Focus();

        // set handled to true to prevent the regular textbox click code from running
        e.Handled = true;
      }
    }

    /// <summary>
    /// this method focuses the textbox and selects all the text. 
    /// One would use this method as the GotFocus
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is tabbed into.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void _TextBox_SelectAll_GotFocus(object sender, RoutedEventArgs e)
    {
      if (sender is TextBox)
      {
        // select all the text
        (sender as TextBox).SelectAll();
      }
    }

    void _ScreensListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      if (e.AddedItems.Count == 1 && e.RemovedItems.Count == 1 && e.AddedItems[0] is IServerObject && e.RemovedItems[0] is IServerObject)
      {
        WozCommitChangesCommand wccc = null;

        if (AutoCommit && e.AddedItems[0] is WozScreen)
        {
          ClientCommittedScreen = e.AddedItems[0] as WozScreen;

          //CommitSelectedScreen();

          wccc = new WozCommitChangesCommand(this);
          //wccc.WozServerCommandReferences = _GenericWozServerCommandReferences;
          wccc.Redo();
          WozServerCommandOccured(wccc);

        }

        WozScreenSelectCommand wozScreenSelectCommand = new WozScreenSelectCommand(this, (e.RemovedItems[0] as IServerObject).ServerID, (e.AddedItems[0] as IServerObject).ServerID, wccc);
        //wozScreenSelectCommand.WozServerCommandReferences = _GenericWozServerCommandReferences;

        WozServerCommandOccured(wozScreenSelectCommand);

        //if (ClientCommittedScreen != null && !(ClientCommittedScreen.Background is VisualBrush) && _ClientRadarCanvas != null)
        //{
        //  //<VisualBrush Stretch="Uniform"
        //  //                                   Visual="{Binding ElementName=_WizardWindow, Path=ClientRadarCanvas}"
        //  //                                   Opacity="0.5"
        //  //                                   />
        //  VisualBrush visualBrush = new VisualBrush(_ClientRadarCanvas);
        //  visualBrush.Stretch = Stretch.Uniform;

        //  visualBrush.Opacity = 0.5;

        //  ClientCommittedScreen.Background = visualBrush;
        //}
      }
    }

    private void WozServerCommandOccured(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      if (!_undoingredoing && !_RunningClientChanges)
      {

        _WizardHistory.Add(wozServerCommand);

        _UndoStack.Push(wozServerCommand);
        _RedoStack.Clear();
      }
    }

    private void WozServerCommandOccuredNoUndo(WozLib.WozCommands.WozCommand wozServerCommand)
    {
      _WizardHistory.Add(wozServerCommand);
    }

    bool _undoingredoing = false;
    public void Undo()
    {
      if (_UndoStack.Count > 0)
      {
        _undoingredoing = true;
        WozLib.WozCommands.WozCommand wozServerCommand = _UndoStack.Pop();
        UndoWozCommand wozUndoCommand = new UndoWozCommand(wozServerCommand);
        WozServerCommandOccuredNoUndo(wozUndoCommand);
        wozServerCommand.Undo();
        _RedoStack.Push(wozServerCommand);

        if (_ClientCommittedScreen == _ScreensListBox.SelectedItem && !AutoCommit && 
          _ClientCommittedScreen.SinceCommitServerCommandStack != null && 
          _ClientCommittedScreen.SinceCommitServerCommandStack.Count == 0)
        {
          _ClientCommittedScreen.InOverlayMode = true;
        }

        _undoingredoing = false;
      }
    }

    public void Redo()
    {
      if (_RedoStack.Count > 0)
      {
        _undoingredoing = true;
        WozLib.WozCommands.WozCommand wozServerCommand = _RedoStack.Pop();
        RedoWozCommand wozRedoCommand = new RedoWozCommand(wozServerCommand);
        WozServerCommandOccuredNoUndo(wozRedoCommand);
        wozServerCommand.Redo();
        _UndoStack.Push(wozServerCommand);

        if (_ClientCommittedScreen == _ScreensListBox.SelectedItem && !AutoCommit &&
          _ClientCommittedScreen.SinceCommitServerCommandStack != null &&
          _ClientCommittedScreen.SinceCommitServerCommandStack.Count == 0)
        {
          _ClientCommittedScreen.InOverlayMode = true;
        }

        _undoingredoing = false;
      }
    }

    void AutoCommitCheck_Unchecked(object sender, RoutedEventArgs e)
    {
      AutoCommitOff();
    }

    void AutoCommitCheck_Checked(object sender, RoutedEventArgs e)
    {
        AutoCommitOn();
    }

    void RealTimeCheck_Unchecked(object sender, RoutedEventArgs e)
    {
      RealTimeOff();
    }

    void RealTimeCheck_Checked(object sender, RoutedEventArgs e)
    {
      RealTimeOn();
    }

    private bool ShouldLogAutoCommit = true;
    public void AutoCommitOn()
    {
      AutoCommitOn(true && ShouldLogAutoCommit);
    }

    public void AutoCommitOff()
    {
      AutoCommitOff(true && ShouldLogAutoCommit);
    }

    private bool ShouldLogRealTime = true;
    public void RealTimeOn()
    {
      RealTimeOn(true && ShouldLogRealTime);
    }

    public void RealTimeOff()
    {
      RealTimeOff(true && ShouldLogRealTime);
    }

    public void AutoCommitOn(bool shouldLog)
    {
      if (this.AutoCommitCheck.IsChecked != true)
      {
        ShouldLogAutoCommit = shouldLog;

        this.AutoCommitCheck.IsChecked = true;

        ShouldLogAutoCommit = true;
      }
      else
      {
        if (shouldLog)
        {
          WozCommitChangesCommand wccc = new WozCommitChangesCommand(this);
          //wccc.WozServerCommandReferences = _GenericWozServerCommandReferences;
          wccc.Redo();

          WozAutoCommitOnCommand wozAutoCommitOnCommand = new WozAutoCommitOnCommand(this,wccc);
          //wozAutoCommitOnCommand.WozServerCommandReferences = _GenericWozServerCommandReferences;

          WozServerCommandOccured(wozAutoCommitOnCommand);
        }
        this.AutoCommit = true;
        CommitButton.IsEnabled = false;
        DiscardButton.IsEnabled = false;
      }
    }

    

    public void AutoCommitOff(bool shouldLog)
    {
      if (this.AutoCommitCheck.IsChecked == true)
      {
        ShouldLogAutoCommit = shouldLog;

        this.AutoCommitCheck.IsChecked = false;

        ShouldLogAutoCommit = true;
      }
      else
      {
        if (shouldLog)
        {
          WozAutoCommitOffCommand wozAutoCommitOffCommand = new WozAutoCommitOffCommand(this);
          //wozAutoCommitOffCommand.WozServerCommandReferences = _GenericWozServerCommandReferences;
          WozServerCommandOccured(wozAutoCommitOffCommand);
        }
        this.AutoCommit = false;
        CommitButton.IsEnabled = true;
        DiscardButton.IsEnabled = true;
      }
    }

    public void RealTimeOn(bool shouldLog)
    {
      if (this.RealTimeCheck.IsChecked != true)
      {
        ShouldLogRealTime = shouldLog;

        this.RealTimeCheck.IsChecked = true;

        ShouldLogRealTime = true;
      }
      else
      {
        // we disable logging the checking of the auto-commit button
        // because we are about to do it programmatically and we don't
        // want that to add to the undo stack
        ShouldLogAutoCommit = false;

        // if we should log then create a WozServerCommand for the UndoRedoStack
        if (shouldLog)
        {
          WozRealTimeOnCommand wozRealTimeOnCommand = new WozRealTimeOnCommand(this, AutoCommitCheck.IsChecked == true);
          //wozRealTimeOnCommand.WozServerCommandReferences = _GenericWozServerCommandReferences;
          WozServerCommandOccured(wozRealTimeOnCommand);
        }

        this.RealtimeCommit = true;
        this.AutoCommit = true;
        AutoCommitCheck.IsChecked = true;
        AutoCommitCheck.IsEnabled = false;

        ShouldLogAutoCommit = true;
      }
    }

    public void RealTimeOff(bool shouldLog)
    {
      if (this.RealTimeCheck.IsChecked == true)
      {
        ShouldLogRealTime = shouldLog;

        this.RealTimeCheck.IsChecked = false;

        ShouldLogRealTime = true;
      }
      else
      {
        // if we should log then create a WozServerCommand for the UndoRedoStack
        if (shouldLog)
        {
          WozRealTimeOffCommand wozRealTimeOffCommand = new WozRealTimeOffCommand(this);
          //wozRealTimeOffCommand.WozServerCommandReferences = _GenericWozServerCommandReferences;
          WozServerCommandOccured(wozRealTimeOffCommand);
        }
        this.RealtimeCommit = false;
        AutoCommitCheck.IsEnabled = true;
      }
    }





    #region IServerObject Members

    public long ServerID
    {
      get
      {
        return _ServerID;
      }
      set
      {
        _ServerID = value;
      }
    } long _ServerID;

    public ServerObject GetServerObject()
    {
      return new WizardWindowWozObject(ServerID);
    }

    #endregion
  }
}